package org.jet.emall.prod.service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.jet.emall.common.restful.result.CommonPage;
import org.jet.emall.prod.custom.dao.ProductDao;
import org.jet.emall.prod.custom.po.AttrPO;
import org.jet.emall.prod.custom.po.SpecPO;
import org.jet.emall.prod.dto.*;
import org.jet.emall.prod.po.*;
import org.jet.emall.prod.service.mp.*;
import org.jet.emall.prod.transfer.SkuDtoTransfer;
import org.jet.emall.prod.transfer.SpuDtoTransfer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * @author xiaozai
 * @version 1.0
 * @date 2020-04-15 10:01
 */
@Service
public class CustomProductServiceImpl implements CustomProductService{

    @Autowired
    private IProdSpuService prodSpuService;

    @Autowired
    private IProdSpuImageService prodSpuImageService;

    @Autowired
    private IProdSkuService prodSkuService;

    @Autowired
    private IProdSkuImageService prodSkuImageService;

    @Autowired
    private IProdSkuAttrOptionService prodSkuAttrOptionService;

    @Autowired
    private IProdSkuSpecOptionService prodSkuSpecOptionService;

    @Autowired
    private IProdAttrOptionService prodAttrOptionService;

    @Autowired
    private IProdSpecOptionService prodSpecOptionService;

    @Autowired
    private ISpuViewService spuViewService;

    @Autowired
    private ProductDao productDao;


    @Override
    public CommonPage<SpuViewDTO> spuPage(String query, Integer pageNum, Integer pageSize, String brandQuery, Integer cateId, Byte banSale) {

        IPage<SpuView> page = new Page<>();
        page.setCurrent(pageNum).setSize(pageSize);
        Wrapper<SpuView> wrapper = new QueryWrapper<>();
        if(StringUtils.isNotBlank(query)){
            ((QueryWrapper<SpuView>) wrapper).like("name",query);
        }
        if(StringUtils.isNotBlank(brandQuery)){
            ((QueryWrapper<SpuView>) wrapper).like("brand_name",brandQuery);
        }
        if(cateId!=null && cateId!=-1){
            ((QueryWrapper<SpuView>) wrapper).eq("cate3_id",cateId);
        }
        if(banSale!=null&& banSale!=-1){
            ((QueryWrapper<SpuView>) wrapper).eq("ban_sale",banSale);
        }
        spuViewService.page(page,wrapper);
        CommonPage<SpuViewDTO> commonPage = new CommonPage<>();
        commonPage.setTotal(page.getTotal())
                .setPageNum(page.getCurrent())
                .setPageSize(page.getSize())
                .setTotalPage(page.getPages())
                .setList(SpuDtoTransfer.INSTANCE.toDtoList(page.getRecords()));
        return commonPage;
    }

    @Override
    public SpuViewDTO findSpuByCode(String spuCode) {
        Wrapper<SpuView> wrapper = new QueryWrapper<>();
        ((QueryWrapper<SpuView>) wrapper).eq("code",spuCode);
        SpuView one = spuViewService.getOne(wrapper);
        SpuViewDTO dto = SpuDtoTransfer.INSTANCE.toDto(one);
        return dto;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveSpu(NewSpuDTO newSpuDTO) {
        ProdSpu prodSpu =  SpuDtoTransfer.INSTANCE.toPo(newSpuDTO);
        prodSpuService.save(prodSpu);
        List<ProdSpuImage> list = new LinkedList<>();
        newSpuDTO.getImages().forEach(image->list.add(new ProdSpuImage().setImage(image).setSpuId(prodSpu.getId())));
        prodSpuImageService.saveBatch(list);



    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void banSale(List<Long> spuIds, Byte banSale) {
        ProdSpu spu = new ProdSpu();
        spu.setBanSale(banSale);
        Wrapper<ProdSpu> wrapper = new UpdateWrapper<>();
        ((UpdateWrapper<ProdSpu>) wrapper).in("id", spuIds);
        prodSpuService.update(spu,wrapper);
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteSpu(List<Long> idList) {
        Wrapper<ProdSku> wrapper = new QueryWrapper<>();
        ((QueryWrapper<ProdSku>) wrapper).in("spu_id", idList);
        prodSkuService.remove(wrapper);
        prodSpuService.removeByIds(idList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteSku(List<Long> idList) {
        prodSkuService.removeByIds(idList);
    }


    @Override
    public SkuDetailsDTO getSkuDetails(Long id) {
        ProdSku sku = prodSkuService.getById(id);
        SkuDetailsDTO detailsDTO = SkuDtoTransfer.INSTANCE.toDetailsDto(sku);
        List<AttrPO> attrPOList = productDao.selectAttrsOfSku(id);
        List<SpecPO> specPOList = productDao.selectSpecsOfSku(id);
        detailsDTO.setAttrs(SkuDtoTransfer.INSTANCE.toAttrDtoList(attrPOList));
        detailsDTO.setSpecs(SkuDtoTransfer.INSTANCE.toSpecDtoList(specPOList));
        Wrapper<ProdSkuImage> wrapper = new QueryWrapper<>();
        ((QueryWrapper<ProdSkuImage>) wrapper).eq("sku_id",id);
        List<ProdSkuImage> list = prodSkuImageService.list(wrapper);
        detailsDTO.setImages(SkuDtoTransfer.INSTANCE.toImageDtoList(list));
        return detailsDTO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateSkuDetails(SkuDetailsDTO dto) {
        // 更新sku主表
        ProdSku prodSku = SkuDtoTransfer.INSTANCE.toPo(dto);
        prodSkuService.updateById(prodSku);

        // 如果图片有，则保存图片
        List<SkuImageDTO> images = dto.getImages();
        if(images!=null || !images.isEmpty()) {
            List<ProdSkuImage> list = SkuDtoTransfer.INSTANCE.toImagePoList(images);
            Wrapper<ProdSkuImage> wrapper = new QueryWrapper<>();
            ((QueryWrapper<ProdSkuImage>) wrapper).eq("sku_id",dto.getId());
            List<ProdSkuImage> prodSkuImages = prodSkuImageService.list(wrapper);
            List<Long> idsInTable = prodSkuImages.stream().mapToLong(image -> image.getId()).collect(ArrayList<Long>::new, List::add, List::addAll);
            List<Long> retainIds = new LinkedList<>();
            list.forEach(image->{
                retainIds.add(image.getId());
                if(image.getId()!=null){
                    return;
                }
                //保存新增的图片
                prodSkuImageService.save(image);
            });
            // 删除一些图片
            idsInTable.removeAll(retainIds);
            prodSkuImageService.removeByIds(idsInTable);
        }
        List<AttrDTO> attrs = dto.getAttrs();
        attrs.forEach(attr -> {
            // 查属性选项值，如果没有改动则不做动作
            ProdAttrOption attrOption = prodAttrOptionService.getById(attr.getAttrOptionId());
            if( attrOption.getVal().equals(attr.getAttrOptionValue())){
                return;
            }
            // 属性选项值有变化
            // 删除sku与变化前的属性选项的关联
            Wrapper<ProdSkuAttrOption> wrapper1 =new QueryWrapper<>();
            ((QueryWrapper<ProdSkuAttrOption>) wrapper1).eq("sku_id",dto.getId())
                    .eq("attr_option_id",attr.getAttrOptionId());
            prodSkuAttrOptionService.remove(wrapper1);

            // 查看该属性选项值是否还有sku与它关联，如果没有则删除这个属性选项值
            Wrapper<ProdSkuAttrOption> wrapper2 = new QueryWrapper<>();
            ((QueryWrapper<ProdSkuAttrOption>) wrapper2).eq("attr_option_id", attr.getAttrOptionId());
            int count = prodSkuAttrOptionService.count(wrapper2);
            if(count==0){
                prodAttrOptionService.removeById(attr.getAttrOptionId());
            }

            // 新建属性选项值
            ProdAttrOption prodAttrOption = new ProdAttrOption();
            prodAttrOption.setVal(attr.getAttrOptionValue());
            prodAttrOption.setAttrId(attr.getAttrId());
            prodAttrOptionService.save(prodAttrOption);

            //新建SKU与新建的属性选项的关联
            ProdSkuAttrOption prodSkuAttrOption = new ProdSkuAttrOption();
            prodSkuAttrOption.setSkuId(dto.getId());
            prodSkuAttrOption.setAttrOptionId(prodAttrOption.getId());
            prodSkuAttrOptionService.save(prodSkuAttrOption);

        });
        List<SpecDTO> specs = dto.getSpecs();
        specs.forEach(spec->{
            //如果规格选项值没改动，则不做动作
            ProdSpecOption specOption = prodSpecOptionService.getById(spec.getSpecOptionId());
            if(specOption.getVal().equals(spec.getSpecOptionValue())){
                return;
            }
            // 规格选项值有改动
            // 删除SKU 与改动前的规格选项的关联
            Wrapper<ProdSkuSpecOption> wrapper1 = new QueryWrapper<>();
            ((QueryWrapper<ProdSkuSpecOption>) wrapper1).eq("sku_id",dto.getId())
                    .eq("spec_option_id",spec.getSpecOptionId());
            prodSkuSpecOptionService.remove(wrapper1);

            // 如果该规格选项没有SKU与之关联，则删除该规格选项
            Wrapper<ProdSkuSpecOption> wrapper2 = new QueryWrapper<>();
            ((QueryWrapper<ProdSkuSpecOption>) wrapper2).eq("spec_option_id",spec.getSpecOptionId());
            int count = prodSkuSpecOptionService.count(wrapper2);
            if(count==0){
                prodSpecOptionService.removeById(spec.getSpecOptionId());
            }

            // 新建规格选项
            ProdSpecOption prodSpecOption = new ProdSpecOption();
            prodSpecOption.setSpecId(spec.getSpecId())
                    .setVal(spec.getSpecOptionValue());
            prodSpecOptionService.save(prodSpecOption);

            // 新建SKU与新建的规格选项关联
            ProdSkuSpecOption prodSkuSpecOption = new ProdSkuSpecOption();
            prodSkuSpecOption.setSkuId(dto.getId()).setSpecOptionId(prodSpecOption.getId());
            prodSkuSpecOptionService.save(prodSkuSpecOption);

        });
    }

    @Override
    public List<SkuDTO> listSkusOfSpu(Long spuId) {
        Wrapper<ProdSku> wrapper = new QueryWrapper<>();
        ((QueryWrapper<ProdSku>) wrapper).eq("spu_id",spuId);
        List<ProdSku> list = prodSkuService.list(wrapper);
        List<SkuDTO> skuDTOList = SkuDtoTransfer.INSTANCE.toDtoList(list);
        return skuDTOList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveSku(NewSkuDTO dto) {
        ProdSku prodSku =  SkuDtoTransfer.INSTANCE.toPo(dto);
        prodSkuService.save(prodSku);
        dto.getAttrs().forEach(attr->{
            //查询是否存在这个属性选项值
            Wrapper<ProdAttrOption> wrapper1 = new QueryWrapper<>();
            ((QueryWrapper<ProdAttrOption>) wrapper1).eq("val",attr.getValue())
                    .eq("attr_id",attr.getId());
            ProdAttrOption prodAttrOption = prodAttrOptionService.getOne(wrapper1);

            //如果这个属性选项值不存在，则新建
            if( prodAttrOption == null){
                prodAttrOption= new ProdAttrOption().setVal(attr.getValue()).setAttrId(attr.getId());
                prodAttrOptionService.save(prodAttrOption);
            }
            //保存新的SKU与这个属性选项值的关联
            ProdSkuAttrOption prodSkuAttrOption = new ProdSkuAttrOption()
                                                    .setSkuId(prodSku.getId())
                                                    .setAttrOptionId(prodAttrOption.getId());
            prodSkuAttrOptionService.save(prodSkuAttrOption);

        });
        dto.getSpecs().forEach(spec->{
            //查询是否存在这个规格选项值
            Wrapper<ProdSpecOption> wrapper1 = new QueryWrapper<>();
            ((QueryWrapper<ProdSpecOption>) wrapper1).eq("val",spec.getValue())
                    .eq("spec_id",spec.getId());
            ProdSpecOption prodSpecOption = prodSpecOptionService.getOne(wrapper1);
            //如果这个规格选项值不存在，则新建
            if(prodSpecOption==null){
                prodSpecOption = new ProdSpecOption().setVal(spec.getValue()).setSpecId(spec.getId());
                prodSpecOptionService.save(prodSpecOption);
            }
            //保存新的SKU与这个规格选项值的关联
            ProdSkuSpecOption prodSkuSpecOption = new ProdSkuSpecOption()
                                                    .setSkuId(prodSku.getId())
                                                    .setSpecOptionId(prodSpecOption.getId());
            prodSkuSpecOptionService.save(prodSkuSpecOption);
        });


    }

    @Override
    public List<SpuImageDTO> getSpuImages(Long spuId) {
        Wrapper<ProdSpuImage> wrapper = new QueryWrapper<>();
        ((QueryWrapper<ProdSpuImage>) wrapper).eq("spu_id",spuId);
        List<ProdSpuImage> list = prodSpuImageService.list(wrapper);
        List<SpuImageDTO> dtoList = SpuDtoTransfer.INSTANCE.toImageDtoList(list);
        return dtoList;
    }

    @Override
    public List<SkuImageDTO> getSkuImages(Long skuId) {
        Wrapper<ProdSkuImage> wrapper = new QueryWrapper<>();
        ((QueryWrapper<ProdSkuImage>) wrapper).eq("sku_id",skuId);
        List<ProdSkuImage> list = prodSkuImageService.list(wrapper);
        List<SkuImageDTO> dtoList = SkuDtoTransfer.INSTANCE.toImageDtoList(list);
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteSpuImages(Long id) {
        prodSpuImageService.removeById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveSpuImage(SpuImageDTO dto) {
        ProdSpuImage prodSpuImage = SpuDtoTransfer.INSTANCE.toImagePo(dto);
        prodSpuImageService.save(prodSpuImage);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveSkuImage(SkuImageDTO dto) {
        ProdSkuImage prodSkuImage = SkuDtoTransfer.INSTANCE.toImagePo(dto);
        prodSkuImageService.save(prodSkuImage);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateSkuPrice(Long skuId, Long price) {
        ProdSku prodSku = new ProdSku();
        prodSku.setId(skuId).setPrice(price);
        prodSkuService.updateById(prodSku);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteSkuImage(Long id) {
        prodSkuImageService.removeById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateSkuName(Long skuId, String name) {
        ProdSku prodSku = new ProdSku();
        prodSku.setId(skuId).setName(name);
        prodSkuService.updateById(prodSku);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateSkuCount(Long skuId, Integer count) {
        ProdSku prodSku = new ProdSku();
        prodSku.setId(skuId).setCount(count);
        prodSkuService.updateById(prodSku);
    }

}
